package top.monddia.netty.server.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import top.monddia.netty.server.config.NettyConfig;
import top.monddia.netty.server.server.initializer.ServerChannelInitializer;

import javax.annotation.Resource;

/**
 * Netty服务端
 *
 * @author ZYP
 */
@Component
public class NettyServer implements CommandLineRunner {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Resource
    private NettyConfig nettyConfig;

    @Resource
    private ServerChannelInitializer serverChannelInitializer;

    @Override
    public void run(String... args) {
        Thread waitThread = new Thread(() -> {
            // 创建bossGroup用于接收连接请求
            EventLoopGroup bossGroup = new NioEventLoopGroup(this.nettyConfig.getBossCount());
            // 创建workGroup用于接收消息数据
            EventLoopGroup workGroup = new NioEventLoopGroup(this.nettyConfig.getWorkCount());
            try {
                // 创建配置参数
                ServerBootstrap serverBootstrap = new ServerBootstrap();
                serverBootstrap
                        // 绑定处理Group
                        .group(bossGroup, workGroup)
                        // Socket通道类
                        .channel(NioServerSocketChannel.class)
                        // 保持连接数
                        .option(ChannelOption.SO_BACKLOG, this.nettyConfig.getSoBacklog())
                        // 保持连接
                        .childOption(ChannelOption.SO_KEEPALIVE, this.nettyConfig.isSoKeepalive())
                        // 处理新连接
                        .childHandler(this.serverChannelInitializer);
                // 绑定并且同步处理
                ChannelFuture channelFuture = serverBootstrap.bind(this.nettyConfig.getHost(), this.nettyConfig.getPort()).sync();
                // 监听到结束信号后关闭
                channelFuture.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                logger.error("Netty服务端启动失败", e);
            } finally {
                bossGroup.shutdownGracefully();
                workGroup.shutdownGracefully();
            }
        });
        waitThread.start();
    }
}
